<template>
  <div class="tinymce-loading-fix-container">
    <!-- 加载状态显示 -->
    <div v-if="isLoading" class="loading-indicator">
      <div class="spinner"></div>
      <p>编辑器加载中...</p>
    </div>

    <!-- 编辑器 -->
    <editor
      v-if="!isLoading"
      v-model="content"
      :init="editorConfig"
      :api-key="apiKey"
      @input="handleInput"
      @init="handleEditorInit"
      @error="handleEditorError"
    />

    <!-- 警告信息 -->
    <div v-if="showWarning" class="warning-message">不能删除全部内容，请至少保留部分内容</div>

    <!-- 错误信息 -->
    <div v-if="showError" class="error-message">
      {{ errorMessage }}
    </div>
  </div>
</template>

<script>
import Editor from '@tinymce/tinymce-vue'

export default {
  components: {
    Editor
  },
  data() {
    return {
      apiKey: '你的TinyMCE API密钥', // 请替换为有效API密钥
      content: `
        <p>这是不能编辑的文本【这部分可以编辑】这部分也不能编辑</p>
        <p>多行示例：
          姓名：【请输入姓名】，
          年龄：【请输入年龄】，
          职业：【请输入职业】
        </p>
      `,
      originalContent: '',
      lastValidContent: '',
      isLoading: true, // 加载状态
      showWarning: false,
      showError: false,
      errorMessage: '',
      isRestoring: false,
      editorInstance: null // 保存编辑器实例
    }
  },
  created() {
    this.originalContent = this.content
    this.lastValidContent = this.content

    // 设置加载超时检测
    this.loadingTimeout = setTimeout(() => {
      if (this.isLoading) {
        this.isLoading = false
        this.showError = true
        this.errorMessage = '编辑器加载超时，请检查网络或API密钥是否有效'
      }
    }, 10000) // 10秒超时
  },
  beforeUnmount() {
    // 清除超时检测
    clearTimeout(this.loadingTimeout)
  },
  computed: {
    editorConfig() {
      const that = this
      return {
        height: 400,
        menubar: 'edit format',
        toolbar: 'undo redo | bold italic | cut copy paste',
        readonly: false,
        extended_valid_elements: 'span[contenteditable|class|id]',
        contextmenu: 'undo redo',
        // 减少不必要的插件，加快加载
        plugins: 'lists link',
        // 禁用自动保存，减少冲突
        autosave_restore_when_empty: false,
        setup: (editor) => {
          that.editorInstance = editor

          // 内容预处理
          editor.on('BeforeSetContent', (e) => {
            e.content = that.processContent(e.content)
          })

          // 内容获取处理
          editor.on('GetContent', (e) => {
            e.content = that.restoreContent(e.content)
          })

          editor.on('init', () => {
            const doc = editor.getDoc()

            // 添加样式
            const style = doc.createElement('style')
            style.textContent = `
              .editable-section {
                border: 1px dashed #42b983;
                padding: 2px 4px;
                margin: 0 2px;
                border-radius: 3px;
                background-color: rgba(66, 185, 131, 0.1);
              }
              .non-editable {
                user-select: text;
              }
            `
            doc.head.appendChild(style)

            that.setNonEditableAreas(editor)
          })

          // 命令执行控制
          editor.on('ExecCommand', (e) => {
            const isInEditable = that.isCursorInEditable(editor)
            const dangerousCommands = ['delete', 'cut', 'backspace', 'mceCut', 'mceDelete']

            if (!isInEditable) {
              e.preventDefault()
              e.stopPropagation()
              return false
            }

            if (dangerousCommands.some((cmd) => e.command.includes(cmd))) {
              const currentContent = editor.getContent()
              const simulatedContent = that.simulateCommand(editor, e.command, currentContent)

              if (that.isContentEmpty(simulatedContent)) {
                e.preventDefault()
                e.stopPropagation()
                that.showWarning = true
                setTimeout(() => (that.showWarning = false), 3000)
                return false
              }
            }
          })

          // 键盘事件
          editor.on('KeyDown', (e) => {
            if (['Delete', 'Backspace', 'x', 'X'].includes(e.key)) {
              if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'x') {
                const selection = editor.selection.getContent()
                const fullContent = editor.getContent({ format: 'text' }).trim()

                if (selection.trim() === fullContent) {
                  e.preventDefault()
                  e.stopPropagation()
                  that.showWarning = true
                  setTimeout(() => (that.showWarning = false), 3000)
                  return false
                }
              }

              if (e.key === 'Delete' || e.key === 'Backspace') {
                that.handleDeleteKey(editor, e)
              }
            }
          })

          // 粘贴事件
          editor.on('Paste', (e) => {
            const isInEditable = that.isCursorInEditable(editor)
            if (!isInEditable) {
              e.preventDefault()
              e.stopPropagation()
              return false
            }

            setTimeout(() => {
              that.checkAndRestoreContent(editor)
            }, 0)
          })

          // 内容变化
          editor.on('Change', () => {
            that.checkAndRestoreContent(editor)
          })

          // 选择区域变化
          editor.on('NodeChange', () => {
            const isInEditable = that.isCursorInEditable(editor)
            that.toggleToolbarButtons(editor, isInEditable)
          })
        }
      }
    }
  },
  methods: {
    // 处理编辑器初始化完成
    handleEditorInit() {
      this.isLoading = false
      clearTimeout(this.loadingTimeout)
    },

    // 处理编辑器错误
    handleEditorError(error) {
      this.isLoading = false
      clearTimeout(this.loadingTimeout)
      this.showError = true
      this.errorMessage = `编辑器加载错误: ${error.message || '未知错误'}`
      console.error('TinyMCE错误:', error)
    },

    // 处理内容标记
    processContent(content) {
      let processed = `<div class="non-editable" contenteditable="false">${content}</div>`
      processed = processed.replace(
        /【([^】]+)】/g,
        (match, text) => `<span class="editable-section" contenteditable="true">${text}</span>`
      )
      return processed
    },

    // 还原内容标记
    restoreContent(content) {
      let restored = content.replace(
        /<div class="non-editable" contenteditable="false">([\s\S]*?)<\/div>/,
        '$1'
      )
      restored = restored.replace(
        /<span class="editable-section" contenteditable="true">([\s\S]*?)<\/span>/g,
        (match, text) => `【${text}】`
      )
      return restored
    },

    // 设置可编辑状态
    setNonEditableAreas(editor) {
      const doc = editor.getDoc()
      const nonEditable = doc.querySelectorAll('.non-editable')
      nonEditable.forEach((el) => {
        el.contentEditable = false
      })
      const editable = doc.querySelectorAll('.editable-section')
      editable.forEach((el) => {
        el.contentEditable = true
      })
    },

    // 判断光标位置
    isCursorInEditable(editor) {
      const node = editor.selection.getNode()
      return node.closest('.editable-section') !== null
    },

    // 切换工具栏
    toggleToolbarButtons(editor, isEnabled) {
      const toolbarButtons = ['bold', 'italic', 'cut', 'copy', 'paste']
      toolbarButtons.forEach((button) => {
        editor.execCommand('mceToggleToolbarItem', false, button, !isEnabled)
      })
    },

    // 判断内容是否为空
    isContentEmpty(content) {
      const text = content
        .replace(/<[^>]+>/g, '')
        .replace(/\s+/g, '')
        .trim()
      return text === ''
    },

    // 处理删除键
    handleDeleteKey(editor, e) {
      const selection = editor.selection.getContent({ format: 'text' }).trim()
      const fullContent = editor.getContent({ format: 'text' }).trim()

      if (selection === fullContent) {
        e.preventDefault()
        e.stopPropagation()
        this.showWarning = true
        setTimeout(() => (this.showWarning = false), 3000)
        return
      }

      if (fullContent.length <= 1 && selection === '') {
        e.preventDefault()
        e.stopPropagation()
        this.showWarning = true
        setTimeout(() => (this.showWarning = false), 3000)
      }
    },

    // 检查并恢复内容
    checkAndRestoreContent(editor) {
      if (this.isRestoring) return

      const currentContent = editor.getContent()

      if (this.isContentEmpty(currentContent)) {
        this.isRestoring = true
        this.showWarning = true

        editor.setContent(this.processContent(this.lastValidContent))
        this.setNonEditableAreas(editor)

        setTimeout(() => {
          this.showWarning = false
          this.isRestoring = false
        }, 3000)
      } else {
        this.lastValidContent = this.restoreContent(currentContent)
      }
    },

    // 模拟命令执行
    simulateCommand(editor, command, currentContent) {
      if (command.includes('delete') || command.includes('cut')) {
        const selection = editor.selection.getContent()
        return currentContent.replace(selection, '')
      }
      return currentContent
    },

    // 处理输入事件
    handleInput(value) {
      if (!this.isRestoring && !this.isContentEmpty(value)) {
        this.lastValidContent = value
      }
    }
  }
}
</script>

<style scoped>
.tinymce-loading-fix-container {
  max-width: 900px;
  margin: 20px auto;
  padding: 0 20px;
}

/* 加载状态样式 */
.loading-indicator {
  text-align: center;
  padding: 40px 0;
  color: #666;
}

.spinner {
  width: 40px;
  height: 40px;
  margin: 0 auto 15px;
  border: 4px solid #f3f3f3;
  border-top: 4px solid #3498db;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

/* 警告信息 */
.warning-message {
  margin-top: 10px;
  padding: 8px 12px;
  background-color: #f8d7da;
  border: 1px solid #f5c6cb;
  border-radius: 4px;
  color: #721c24;
  font-size: 14px;
  animation: fadein 0.3s, fadeout 0.3s 2.7s;
}

/* 错误信息 */
.error-message {
  margin-top: 10px;
  padding: 10px 15px;
  background-color: #ffebee;
  border: 1px solid #ef9a9a;
  border-radius: 4px;
  color: #c62828;
  font-size: 14px;
}

@keyframes fadein {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes fadeout {
  from {
    opacity: 1;
    transform: translateY(0);
  }

  to {
    opacity: 0;
    transform: translateY(-10px);
  }
}
</style>
